﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Mimoza.ServiceLayer
{
    /// <summary>
    /// Class for initiating connection with hosts. 
    /// </summary>
    public class HostsConnectionInitiator : BaseObject
    {
        public HostsConnectionInitiator(Configuration config, HostsConnections hostsConnections)
            : base(config)
        {
            m_hostsConnections = hostsConnections;
        }

        override public void Init()
        {
            FillServerLocalAddresses();
        }

        override public void Shutdown()
        {
            StopWorkingThread();
        
        }

        public HostsConnections HostsConnections 
        {
            get { return m_hostsConnections; }
        }

                /// <summary>
        /// Add host in queue of sending connection signal. 
        /// </summary>
        public void AddHost(ObjectLayer.Host host)
        {
            string hostIpAddr = GetAddr(host);
            int udpPort = Configuration.Settings.BroadcastTransportPort;
            if (IsLocalServerAddr(hostIpAddr)) udpPort += 1;

            HostConnectionInfo connInfo = new HostConnectionInfo(host.ID.ToString(),
                hostIpAddr, udpPort);

            AddHost(connInfo);
        }

        /// <summary>
        /// Add host in queue of sending connection signal. 
        /// </summary>
        public void AddHost(HostConnectionInfo hostConnInfo)
        {
            lock (m_hostsQueue)
            {
                Common.Logger.Log.Info("HostsConnectionInitiator.AddHost id - '" +
                    hostConnInfo.Id + "' address - '" + hostConnInfo.Address + "' upd port - " + 
                    hostConnInfo.UdpPort.ToString() + "'.");

                m_hostsQueue.Enqueue(hostConnInfo);
                    StartWorkingThread();
            }
        }


        /// <summary>
        /// Get list of host for intiate
        /// </summary>
        public HostConnectionInfo[] HostsToInitiate
        {
            get { return m_hostsQueue.ToArray(); }
        }

        /// <summary>
        /// Returns number of sended signals
        /// </summary>
        public int SendSignalCount
        {
            get { return m_sendSignalCount; }
        }


        void StartWorkingThread()
        {
            lock (this)
            {
                m_bStopThread = false;
                if (m_thread == null)
                {
                    m_thread = new System.Threading.Thread(
                        new System.Threading.ThreadStart(DoWork));
                    m_thread.Start();
                }
            }
        }

        void StopWorkingThread()
        {
            System.Threading.Thread thread = StopWorkingThreadWithoutWait();

            if (thread != null) thread.Join();
        }

        System.Threading.Thread StopWorkingThreadWithoutWait()
        {
            System.Threading.Thread thread = null;
            lock (this)
            {
                if (m_thread != null)
                {
                    thread = m_thread;
                    m_thread = null;
                    m_bStopThread = true;
                }
            }
            
            return thread;
        }

        void DoWork()
        {
            bool bHasConn = false;
            do
            {
                HostConnectionInfo connInfo = null;
                lock (this)
                {   
                    connInfo = m_hostsQueue.Dequeue();
                    if (m_bStopThread && connInfo == null) bHasConn = false;
                    else bHasConn = true;
                }

                SendConnectionSignal(connInfo);
            }
            while (bHasConn && m_hostsQueue.Count>0);

            StopWorkingThreadWithoutWait();
        }

        void SendConnectionSignal(HostConnectionInfo connInfo)
        {
            m_sendSignalCount++;

            m_hostsConnections.SendInitiateConnectionSignal(connInfo.Id,
                connInfo.Address, connInfo.UdpPort);
        }

        void FillServerLocalAddresses()
        {
            m_localIpAddresses = Common.ArrayToString.ToString(
                Transport.LocalInfo.GetAdapters().GetIPAddresses());
        }

        bool IsLocalServerAddr(string hostAddr)
        {
            return (m_localIpAddresses.IndexOf(hostAddr) >= 0);
        }

        static string GetAddr(ObjectLayer.Host host)
        {
            string[] array = Common.ArrayToString.FromString(host.IPAddress);
            if (array != null && array.Length > 0) return array[0];
            else return "";
        }

        string m_localIpAddresses = "";
        System.Threading.Thread m_thread;
        bool m_bStopThread = false;
        Queue<HostConnectionInfo> m_hostsQueue = new Queue<HostConnectionInfo>();
        HostsConnections m_hostsConnections;
        int m_sendSignalCount = 0;
    }
}
